using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace SqlTools.SchemaReader
{
	/// <summary>
	/// Indicates the type of database object a particular derived class represents
	/// </summary>
	public enum DbObjectType
	{
		/// <summary>
		/// A check constraint
		/// </summary>
		Check,

		/// <summary>
		/// A table or view column
		/// </summary>
		Column,

		/// <summary>
		/// The database its self
		/// </summary>
		Database,

		/// <summary>
		/// The base class
		/// </summary>
		/// <remarks>No instance should ever have this value</remarks>
		DbObject,

		/// <summary>
		/// A default column value
		/// </summary>
		Default,

		/// <summary>
		/// A table foreign key
		/// </summary>
		ForeignKey,

		/// <summary>
		/// A table index
		/// </summary>
		Index,

		/// <summary>
		/// A stored procedure parameter
		/// </summary>
		Parameter,

		/// <summary>
		/// A table primary key
		/// </summary>
		PrimaryKey,

		/// <summary>
		/// A stored procedure
		/// </summary>
		StoredProcedure,

		/// <summary>
		/// A database table
		/// </summary>
		Table,

		/// <summary>
		/// A database view
		/// </summary>
		View
	}

	public class DbObject
	{
		protected string _name;
		protected int _id;

		public DbObject() : this("", 0) { }
		
		/// <summary>
		/// The base class constructor. All derived classes must call this constructor
		/// </summary>
		/// <param name="name">The name of this database object</param>
		/// <param name="id">The id used internally within Sql Server for this object</param>
		public DbObject(string name, int id)
		{
			_name = name;
			_id = id;
		}

		/// <summary>
		/// The name of this particular DB object.
		/// </summary>
		public string Name
		{
			get { return _name; }
		}

		/// <summary>
		/// The internal ID of this object.
		/// </summary>
		/// <remarks>This value represents different things depending on the
		/// object type.  For tables, views, stored procedures, and a few others,
		/// this is a value unique for this database.  For columns, index keys, 
		/// and a few some other types, this is unique to its parent container.</remarks>
		internal int ID
		{
			get { return _id; }
		}

		/// <summary>
		/// Returns the type of this object instance.
		/// </summary>
		public virtual DbObjectType Type
		{
			get { return DbObjectType.DbObject; }
		}

		/// <summary>
		/// Saves the schema represented by this object to XML.
		/// </summary>
		/// <param name="doc">An existing XmlDocument with a defined document element</param>
		/// <param name="xmlParent">The parent element that will contain this objects
		/// schema</param>
		public virtual void SaveXml(XmlDocument doc, XmlNode xmlParent)
		{
			CreateXmlElement(doc, xmlParent);
		}

		/// <summary>
		/// Creates the default xml element for this type, with information from
		/// this base class
		/// </summary>
		/// <param name="doc">An existing XmlDocument with a defined document element</param>
		/// <param name="parent">The parent element that will contain this object</param>
		/// <returns>The Xml Element that represents this object.</returns>
		public virtual XmlElement CreateXmlElement(XmlDocument doc, XmlNode parent)
		{
			XmlElement xmlRoot = doc.CreateElement(this.GetType().Name);

			xmlRoot.Attributes.Append(doc.CreateAttribute("name")).Value = _name;
			xmlRoot.Attributes.Append(doc.CreateAttribute("id")).Value = _id.ToString();

			parent.AppendChild(xmlRoot);

			return xmlRoot;
		}

		/// <summary>
		/// Loads the base data from this particular element
		/// </summary>
		/// <param name="el">The xml element representing this object</param>
		/// <param name="db">An existing DB object, or null for the Database object</param>
		public virtual void LoadXml(XmlElement el, Database db)
		{
			_name = el.GetAttribute("name");

			string id = el.GetAttribute("id");

			if ( !int.TryParse(id, out _id) )
			{
				_id = 0;
			}
		}

		/// <summary>
		/// Returns the name of the DB object for the default ToString()
		/// </summary>
		/// <returns>The name of this DB object</returns>
		public override string ToString()
		{
			return _name;
		}
	}
}
